#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <pthread.h>

#include "../12_CPQuestion/ObeCP/Task.hpp"

//线程个数的缺省值
static const size_t defaultNum = 10;

//描述线程的结构体
struct ThreadInfo
{
    pthread_t tid;   
    std::string name;
};

template<class T>
class ThreadPool
{
public:
    //多线程的单例模式（懒汉模式）下也需要加锁创建对象。
    //获取单例对象
    static ThreadPool<T>* GetInstance()
    {
        //套一层的原因是：如果已经有对象了，就不需要加锁创建了，可以在用一层判断是否为空，跳过加锁判断。
        //否则就算是已经有对象了，也需要加锁进行判断
        if(_tp = nullptr)
        {
            //加锁保证单线程进入判断，单线程创建对象。
            pthread_mutex_lock(&_mtx);
            if(_tp == nullptr)
            {
                _tp = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&_mtx);
        }
        return _tp;
    }

    //构建num个线程
    void Start()
    {
        int num = _threads.size();
        for(int i = 0; i < num; i++)
        {
            _threads[i].name = "thread-" + std::to_string(i + 1);
            pthread_create(&(_threads[i].tid), nullptr, HandlerTask, this);
        }
    }

    //线程函数
    static void* HandlerTask(void* args)
    {
        ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(args);
        std::string name = tp->GetThreadName(pthread_self());
        while(true)
        {
            pthread_mutex_lock(&(tp->_mtx));
            while(tp->_tasks.empty())
            {
                //这里设置为循环的原因是：当线程被唤醒时，又有新的线程进来，和他一起争夺锁，他没有抢到，
                //那么资源可能会被其他线程取走，等他申请到锁之后，还是没有资源，就又要进入等待，所以用while循环。
                pthread_cond_wait(&(tp->_cond), &(tp->_mtx));
            }
            T t = tp->Pop();
            pthread_mutex_unlock(&(tp->_mtx));
            t();
        }
    }

    //线程执行任务函数
    T Pop()
    {
        //这里不加锁，是因为只有线程函数可以调用Pop，那里已经加过锁了
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }
    //将任务放入队列
    void Push(T t)
    {
        pthread_mutex_lock(&(tp->_mtx));
        _tasks.push(t);
        pthread_cont_signal(&_cond);
        pthread_mutex_unlock(&(tp->_mtx));
    }

private:
    std::vector<ThreadInfo> _threads;    //管理线程的数组
    std::queue<T> _tasks;                //任务队列
    pthread_cond_t _cond;
    
    //单例模式
    static ThreadPool<T>* _tp;
    static pthread_mutex_t _mtx; 

private:
    ThreadPool(const size_t num = defaultNum)
    :_threads(num)
    {
        //初始化锁和条件变量
        pthread_cond_init(&_cond, nullptr);
        pthread_mutex_init(&_mtx, nullptr);
    }

    ThreadPool(const ThreadPool<T>&) = delete;
    ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;

    ~ThreadPool()
    {
        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_mtx);
    }

    std::string GetThreadName(pthread_t tid)
    {
        int num = _threads.size();
        for(int i = 0; i < num; i++)
        {
            if(_threads[i].tid == tid)
                return _threads[i].name;
        }
        return NONE;
    }
};

template<class T>
ThreadPool<T>* ThreadPool<T>::_tp = nullptr;
template<class T>
pthread_mutex_t ThreadPool<T>::_mtx = PTHREAD_MUTEX_INITIALIZER;